package it.azienda.stampe.controllo;

import it.azienda.framework.persistenza.DAOConnectionSingleton;
import it.azienda.framework.utilita.Utilita;
import it.azienda.stampe.parametri.BeanStampa;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;

import javax.swing.JList;
import net.sf.jasperreports.engine.JRExporter;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperPrintManager;
import net.sf.jasperreports.engine.export.JRCsvExporter;
import net.sf.jasperreports.engine.export.JRCsvExporterParameter;
import net.sf.jasperreports.engine.export.JRHtmlExporter;
import net.sf.jasperreports.engine.export.JRXlsExporter;
import net.sf.jasperreports.engine.export.JRXlsExporterParameter;
import net.sf.jasperreports.engine.export.JRXmlExporter;
import net.sf.jasperreports.view.JRViewer;

import org.hibernate.Session;
import org.jdom.Attribute;
import org.jdom.CDATA;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;

public class CompilatoreJasper {

    public static String pathJasper = null;
    private ArrayList listaFileJasper = new ArrayList();
    private JasperPrint jasperPrint;
    private JRExporter exporter;
    private BeanStampa beanStampa;
    private Session sess = null;
    private MyDataSource dataSource;
    private java.lang.Long idStampaCorrente = new java.lang.Long(System.currentTimeMillis());

    // MAIN
    public void main(BeanStampa beanStampa1) {

        JList list = new JList();
        dataSource = new MyDataSource(list);

        this.beanStampa = beanStampa1;
        this.stampaReport();

    }

    public void stampaReport() {

        try {
            // ANALISI
            analisiStampa();

            // OUTPUT
            outputStampa();

            // SALVATAGGIO
            salvataggioStampa();

        } catch (Exception ex) {
            ex.printStackTrace();
            FacesContext ctx = FacesContext.getCurrentInstance();
            Utilita.getRequest().setAttribute("errore", "Errore nella Stampa: " + ex.toString());
            String url2 = "/errore.jsf";
            UIViewRoot view = ctx.getApplication().getViewHandler().createView(ctx, url2);
            view.setViewId(url2);
            ctx.setViewRoot(view);
            ctx.renderResponse();
        } finally {
            // ELIMINAZIONE JASPER
            eliminaFileJasper();
        }
    }

    // ANALISI FILE STAMPA
    private void analisiStampa() throws Exception {
        if (this.beanStampa.getTipoStampa().intValue() != 1) { //File .jrxml
            // FILE JRXML
            String reportSource = pathJasper + "/" + this.beanStampa.getNomeStampa() + ".jrxml";
            Document documento = null;
            SAXBuilder saxBuilder = new SAXBuilder();
            documento = saxBuilder.build(reportSource);

            if (this.beanStampa.getQueryNuova() != null) {
                documento = scansioneFile(documento, this.beanStampa.getQueryNuova());
            }

            // Analizziamo il file ricorsivamente per vedere se ci sono subreports
            jasperPrint = analizeSubReports(documento, this.beanStampa.getNomeStampa() + ".jrxml");
        }
    }

    // OUTPUT STAMPA
    private void outputStampa() throws Exception {
        FacesContext ctx = FacesContext.getCurrentInstance();

        if (this.beanStampa.getTipoOutput().intValue() == 0) {
            //PDF
            byte[] bytes = JasperExportManager.exportReportToPdf(jasperPrint);
            Utilita.getRequest().setAttribute("byte", bytes);
            String nomeFile = this.beanStampa.getNomeStampa() + ".pdf";
            Utilita.getRequest().setAttribute("file", nomeFile);
            String url2 = "/pages_stampe/visualizzaPdf.jsf";
            UIViewRoot view = ctx.getApplication().getViewHandler().createView(ctx, url2);
            view.setViewId(url2);
            ctx.setViewRoot(view);
            ctx.renderResponse();
        } else if (this.beanStampa.getTipoOutput().intValue() == 1) {
            //HTML
            exporter = new JRHtmlExporter();
            byte[] bytes = null;
            bytes = exportReportToBytes(jasperPrint, exporter);
            String nomeFile = this.beanStampa.getNomeStampa() + ".html";

        } else if (this.beanStampa.getTipoOutput().intValue() == 1) {
            //HTML
            exporter = new JRHtmlExporter();
            byte[] bytes = null;
            bytes = exportReportToBytes(jasperPrint, exporter);
            Utilita.getRequest().setAttribute("byte", bytes);

            String nomeFile = this.beanStampa.getNomeStampa() + ".html";
            Utilita.getRequest().setAttribute("file", nomeFile);
            String url2 = "/pages_stampe/visualizzaHtml.jsf";
            UIViewRoot view = ctx.getApplication().getViewHandler().createView(ctx, url2);
            view.setViewId(url2);
            ctx.setViewRoot(view);
            ctx.renderResponse();
        } else if (this.beanStampa.getTipoOutput().intValue() == 2) {
            //XML
            exporter = new JRXmlExporter();
            byte[] bytes = null;
            bytes = exportReportToBytes(jasperPrint, exporter);
            Utilita.getRequest().setAttribute("byte", bytes);

            String nomeFile = this.beanStampa.getNomeStampa() + ".xml";
            Utilita.getRequest().setAttribute("file", nomeFile);
            String url2 = "/pages_stampe/visualizzaXml.jsf";
            UIViewRoot view = ctx.getApplication().getViewHandler().createView(ctx, url2);
            view.setViewId(url2);
            ctx.setViewRoot(view);
            ctx.renderResponse();
        } else if (this.beanStampa.getTipoOutput().intValue() == 3) {
            //Excel
            exporter = new JRXlsExporter();
            byte[] bytes = null;
            bytes = exportReportToBytes(jasperPrint, exporter);
            Utilita.getRequest().setAttribute("byte", bytes);

            String nomeFile = this.beanStampa.getNomeStampa() + ".xls";
            Utilita.getRequest().setAttribute("file", nomeFile);
            String url2 = "/pages_stampe/visualizzaExcel.jsf";
            UIViewRoot view = ctx.getApplication().getViewHandler().createView(ctx, url2);
            view.setViewId(url2);
            ctx.setViewRoot(view);
            ctx.renderResponse();
        } else if (this.beanStampa.getTipoOutput().intValue() == 4) {
            //CSV
            exporter = new JRCsvExporter();
            byte[] bytes = null;
            bytes = exportReportToBytes(jasperPrint, exporter);
            Utilita.getRequest().setAttribute("byte", bytes);
            String nomeFile = this.beanStampa.getNomeStampa() + ".csv";
            Utilita.getRequest().setAttribute("file", nomeFile);
            String url2 = "/pages_stampe/visualizzaCsv.jsf";
            UIViewRoot view = ctx.getApplication().getViewHandler().createView(ctx, url2);
            view.setViewId(url2);
            ctx.setViewRoot(view);
            ctx.renderResponse();
        } else if (this.beanStampa.getTipoOutput().intValue() == 5) {
            //TXT
            //exporter = new JRTextExporter();
            exporter = new JRCsvExporter();
            jasperPrint.setPageWidth(150);
            byte[] bytes = null;
            bytes = exportReportToBytes(jasperPrint, exporter);
            Utilita.getRequest().setAttribute("byte", bytes);
            String nomeFile = this.beanStampa.getNomeStampa() + ".txt";
            Utilita.getRequest().setAttribute("file", nomeFile);
            String url2 = "/pages_stampe/visualizzaCsv.jsf";
            UIViewRoot view = ctx.getApplication().getViewHandler().createView(ctx, url2);
            view.setViewId(url2);
            ctx.setViewRoot(view);
            ctx.renderResponse();
        } else if (this.beanStampa.getTipoOutput().intValue() == 5) {
            //STAMPA DIRETTA
            JasperPrintManager.printReport(jasperPrint, true);
        } else if (this.beanStampa.getTipoOutput().intValue() == 6) {
            //STAMPA con visualizzatore
            JRViewer viewr = new JRViewer(jasperPrint);
        } else {
            //nessuna Stampa
        }
    }

    // SALVATAGGIO
    private void salvataggioStampa() throws Exception {
        String base = System.getenv("Utils_ManagerWork");
        if (this.beanStampa.getTipoSalvataggio().intValue() == 1) {
            //Esport in Pdf
            JasperExportManager.exportReportToPdfFile(jasperPrint, base + "/" + this.beanStampa.getNomeStampa() + ".pdf");
        } else if (this.beanStampa.getTipoSalvataggio().intValue() == 2) {
            //Esport in html
            JasperExportManager.exportReportToHtmlFile(jasperPrint, base + "/" + this.beanStampa.getNomeStampa() + ".html");
        } else if (this.beanStampa.getTipoSalvataggio().intValue() == 3) {
            //Esport in Xml
            JasperExportManager.exportReportToXmlFile(jasperPrint, base + "/" + this.beanStampa.getNomeStampa() + ".xml", false);
        } else if (this.beanStampa.getTipoSalvataggio().intValue() == 4) {
            //Esport in Excel
            OutputStream ouputStream = new FileOutputStream(new File(base + "/" + this.beanStampa.getNomeStampa() + ".xls"));
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            JRXlsExporter exporterXLS = new JRXlsExporter();
            exporterXLS.setParameter(JRXlsExporterParameter.JASPER_PRINT, jasperPrint);
            exporterXLS.setParameter(JRXlsExporterParameter.OUTPUT_STREAM, byteArrayOutputStream);
            exporterXLS.exportReport();
            ouputStream.write(byteArrayOutputStream.toByteArray());
            ouputStream.flush();
            ouputStream.close();
        } else if (this.beanStampa.getTipoSalvataggio().intValue() == 5) {
            //Esport in Csv
            OutputStream ouputStream = new FileOutputStream(new File(base + "/" + this.beanStampa.getNomeStampa() + ".csv"));
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            JRCsvExporter exporterCsv = new JRCsvExporter();
            exporterCsv.setParameter(JRCsvExporterParameter.JASPER_PRINT, jasperPrint);
            exporterCsv.setParameter(JRCsvExporterParameter.OUTPUT_STREAM, byteArrayOutputStream);
            exporterCsv.exportReport();
            ouputStream.write(byteArrayOutputStream.toByteArray());
            ouputStream.flush();
            ouputStream.close();
        }
    }

    // ANALISI RICORSIVA SUBREPORTS
    private JasperPrint analizeSubReports(Document document, String pathFileReport) throws Exception {
        JasperPrint jasperPrintROOT = null;
        ByteArrayInputStream inputStream = null;
        Element root = document.getRootElement();
        List rooChildren = root.getChildren();
        ArrayList listaSubreport = new ArrayList();
        for (int i = 0; i < rooChildren.size(); i++) {
            Element rootChild = (Element) rooChildren.get(i);
            if (rootChild != null) {
                Element band = rootChild.getChild("band");
                if (band != null) {
                    List listaSubreportBand = band.getChildren("subreport");
                    if (listaSubreportBand != null) {
                        listaSubreport.addAll(listaSubreportBand);
                    }
                }
            }
        }

        if (listaSubreport != null) {
            for (int i = 0; i < listaSubreport.size(); i++) {
                Element subreport = (Element) listaSubreport.get(i);
                if (subreport != null) {
                    Element subreportExpression = subreport.getChild("subreportExpression");
                    if (subreportExpression != null) {
                        String testo = subreportExpression.getText();
                        if (testo != null) {
                            if (testo.contains("$P")) {
                                StringTokenizer tknString = new StringTokenizer(testo, "\"", false);
                                tknString.nextToken();
                                String pathSubReportJasper = tknString.nextToken();
                                if (pathSubReportJasper != null) {
                                    String pathSubReportJrxml = pathSubReportJasper.substring(0, pathSubReportJasper.indexOf(".jasper")) + ".jrxml";
                                    String reportSource = pathJasper + "/" + pathSubReportJrxml;

                                    // Eliminiamo il vecchio contenuto di subreportExpression
                                    subreportExpression.removeContent();

                                    // Mettiamo il nuovo contenuto
                                    CDATA c = new CDATA("$P{SUBREPORT_DIR} + " + "\"" + pathSubReportJasper.substring(0, pathSubReportJasper.indexOf(".jasper")) + "_" + idStampaCorrente + ".jasper" + "\"");
                                    subreportExpression.addContent(c);

                                    Document documentoSubreport = null;
                                    SAXBuilder saxBuilder = new SAXBuilder();
                                    documentoSubreport = saxBuilder.build(reportSource);
                                    analizeSubReports(documentoSubreport, pathSubReportJrxml);
                                    System.out.println("Analizzo--> " + pathSubReportJrxml);
                                }
                            } else {
                                StringTokenizer tknString = new StringTokenizer(testo, "/", false);
                                while (tknString.hasMoreTokens()) {
                                    String pathSubReportJasper = tknString.nextToken();
                                    if (pathSubReportJasper.contains(".jasper")) {
                                        StringTokenizer tknString2 = new StringTokenizer(pathSubReportJasper, ".jasper", false);
                                        pathSubReportJasper = tknString2.nextToken();
                                        if (pathSubReportJasper != null) {
                                            String pathSubReportJrxml = pathSubReportJasper.substring(0, pathSubReportJasper.indexOf(".jasper")) + ".jrxml";
                                            String reportSource = pathJasper + "/" + pathSubReportJrxml;
                                            Document documentoSubreport = null;
                                            SAXBuilder saxBuilder = new SAXBuilder();
                                            documentoSubreport = saxBuilder.build(reportSource);
                                            analizeSubReports(documentoSubreport, pathSubReportJrxml);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

        }
        // SETTIAMO PARAMETRI DI DEFAULT IN XML
        setSubDirDefault(document, pathJasper + "/", pathFileReport);

         // Compilazione
        byte[] bytes = null;

        ByteArrayInputStream in = null;

        document.getDocType().setSystemID(pathJasper + "/jasperreport.dtd");

        ByteArrayOutputStream out = new ByteArrayOutputStream();

        new org.jdom.output.XMLOutputter().output(document, out);

        bytes = out.toByteArray();

        in = new ByteArrayInputStream(bytes);

        String pathReport = pathFileReport.substring(0, pathFileReport.indexOf(".jrxml"));
        String pathFileJasper = pathJasper + "/" + pathReport + "_" + idStampaCorrente + ".jasper";
        listaFileJasper.add(pathFileJasper);

        ByteArrayOutputStream outJasper = new ByteArrayOutputStream();

        System.setProperty("jasper.reports.compile.class.path", (String) Utilita.getRequest().getSession().getServletContext().getAttribute("org.apache.catalina.jsp_classpath"));
        //System.setProperty("org.xml.sax.driver", "org.apache.xerces.parsers.SAXParser");
        JasperCompileManager.compileReportToStream(in, outJasper);

        FileOutputStream fileOutputStream = new FileOutputStream(pathFileJasper);
        fileOutputStream.write(outJasper.toByteArray());

        fileOutputStream.flush();
        fileOutputStream.close();

        inputStream = new ByteArrayInputStream(outJasper.toByteArray());
        //PARAMETRI
        HashMap params = new HashMap();
        params.put("SUBREPORT_DIR", pathJasper + "/");

        if (!pathReport.equals(this.beanStampa.getNomeStampa())) {
            sess = DAOConnectionSingleton.newSession();
            DAOConnectionSingleton.beginTransaction();
            JasperPrint jasperPrint = JasperFillManager.fillReport(inputStream, params, sess.connection());
            DAOConnectionSingleton.commitTransaction();
            jasperPrintROOT = jasperPrint;
        } else {
            //Settaggio Parametri per la Stampa
            HashMap paramsStampa = new HashMap();
            if (this.beanStampa.getParametriStampa() != null) {
                paramsStampa = this.beanStampa.getParametriStampa();
            }
            paramsStampa.put("SUBREPORT_DIR", pathJasper + "/");

            if (this.beanStampa.getTipoReport().intValue() == 0) {
                sess = DAOConnectionSingleton.newSession();
                DAOConnectionSingleton.beginTransaction();
                JasperPrint jasperPrint = JasperFillManager.fillReport(inputStream, paramsStampa, sess.connection());
                DAOConnectionSingleton.commitTransaction();
                jasperPrintROOT = jasperPrint;
            } else {
                //Con la classe dataSource
                JasperPrint jasperPrint = JasperFillManager.fillReport(inputStream, paramsStampa, dataSource);
                jasperPrintROOT = jasperPrint;
            }
        }
        return jasperPrintROOT;
    }

    // Settiamo valori di default per SUBDIR
    private void setSubDirDefault(Document document, String path, String nomeFile) throws Exception {
        Element root = document.getRootElement();
        List listaFigli = root.getChildren("parameter");
        Iterator iteratore = listaFigli.iterator(); // iteratore da java.util!
        while (iteratore.hasNext()) {
            Element parameter = (Element) iteratore.next();
            Attribute name = parameter.getAttribute("name");
            if (name.getValue().equals("SUBREPORT_DIR")) {
                parameter.removeChild("defaultValueExpression");
                Element defaultValueExpression = new Element("defaultValueExpression");
                String esitoPath = "";
                String[] split = path.split("|");
                for (int i = 0; i < split.length; i++) {
                    String valore = split[i];
                    if (valore.equals("\\")) {
                        esitoPath += "/";
                    } else {
                        esitoPath += valore;
                    }
                }
                CDATA c = new CDATA("\"" + esitoPath + "\"");
                defaultValueExpression.setContent(c);
                parameter.addContent(defaultValueExpression);

                // Salvataggio fisico
                /*
                 FileOutputStream fileOutputStream = new FileOutputStream(path + nomeFile);
                 XMLOutputter xmlOutputter = new XMLOutputter();
                 xmlOutputter.output(document,fileOutputStream);
                 fileOutputStream.flush();
                 fileOutputStream.close();
                 */
                break;
            }
        }
    }

    // Eliminazione file jasper
    private void eliminaFileJasper() {
        try {
            for (int i = 0; i < listaFileJasper.size(); i++) {
                String pathFileJasper = (String) listaFileJasper.get(i);
                File fileJasper = new File(pathFileJasper);
                fileJasper.delete();
            }
        } catch (Exception e) {
            System.out.println("Esito Elimina File:" + e.toString());
        }

        listaFileJasper = new ArrayList();
    }

    private Document scansioneFile(Document document, String qNuova) {
        Element root = document.getRootElement();
        List listaFigli = root.getChildren();
        Iterator iteratore = listaFigli.iterator();
        while (iteratore.hasNext()) {
            Element element = (Element) iteratore.next();
            if (element.getName().equals("queryString")) {
                CDATA query = (CDATA) element.getContent().get(0);
                String qVecchia = query.getText();
                element.removeContent();
                CDATA queryNuova = new CDATA(qNuova);
                element.addContent(queryNuova);
                return document;
            }
        }
        return document;
    }

    private byte[] exportReportToBytes(JasperPrint jasperPrint, JRExporter exporter) throws Exception {
        byte[] output;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
        exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos);

        exporter.exportReport();

        output = baos.toByteArray();
        return output;
    }

}
